#include "common.h"
#include "param.h"

#define BACK_LOG 10
#define BUFF_SIZE 1024

class TcpServer  
{
  public:
    TcpServer(const int port)
      :_port(port)
      ,_listenSock(-1)
    {}

    ~TcpServer()
    {
      if(_listenSock >= 0)
      {
        close(_listenSock);
      }
    }

    void InitServer()
    {
      // 1、创建套接字
      _listenSock = socket(AF_INET, SOCK_STREAM, 0);
      // 2、绑定套接字
      struct sockaddr_in local;
      memset(&local, 0, sizeof(local));
      local.sin_family = AF_INET;
      local.sin_port = htons(_port);
      local.sin_addr.s_addr = INADDR_ANY;
      bind(_listenSock, (struct sockaddr*)&local, sizeof(local));
      // 3、设置监听套接字
      listen(_listenSock, BACK_LOG);
    }

    // 服务客户端
    static void Service(const int linkSock, const string& ip, const int port)
    {
      char buff[BUFF_SIZE];

      while(1)
      {
        ssize_t size = read(linkSock, buff, sizeof(buff)-1);
        if(size > 0)
        {
          buff[size] = 0;
          cout<<'['<<ip<<':'<<port<<"]# "<<buff<<endl;
          write(linkSock, buff, size);
        }
        else if(size == 0)
        {
          cout<<"client close!"<<endl;
          break;
        }
        else 
        {
          cerr<<"read error"<<endl;
          break;
        }
      }
      // 服务完成后要记得关闭该连接套接字
      close(linkSock);
    }


    // 多进程并发版本1
    //// 启动服务器
    //void LoopServer()
    //{
    //  // 主进程忽略对SIGCHLD信号的处理
    //  signal(SIGCHLD, SIG_IGN);

    //  struct sockaddr_in peer;
    //  memset(&peer, 0, sizeof(peer));
    //  socklen_t len = sizeof(peer);

    //  // 不断地监听获取客户端的连接请求
    //  while(1)
    //  {
    //    int linkSock = accept(_listenSock, (struct sockaddr*)&peer, &len);
    //    // 若该套接字监听失败，继续监听下一个套接字即可
    //    if(linkSock == -1)
    //    {
    //      cout<<"accept error, continue next link"<<endl;
    //      continue;
    //    }
    //    int port = ntohs(peer.sin_port);
    //    string ip = inet_ntoa(peer.sin_addr);
    //    cout<<"get a new link, sockfd is "<<linkSock<<endl;
    //    // 连接成功后，创建子进程为客户端提供服务
    //    if(fork() == 0)
    //    {
    //      close(_listenSock);
    //      Service(linkSock, ip, port);
    //      exit(0);
    //    }
    //    close(linkSock);
    //  }


    // 多进程并发版本2
    // 启动服务器
    //void LoopServer()
    //{
    //  struct sockaddr_in peer;
    //  memset(&peer, 0, sizeof(peer));
    //  socklen_t len = sizeof(peer);

    //  // 不断地监听获取客户端的连接请求
    //  while(1)
    //  {
    //    int linkSock = accept(_listenSock, (struct sockaddr*)&peer, &len);
    //    // 若该套接字监听失败，继续监听下一个套接字即可
    //    if(linkSock == -1)
    //    {
    //      cout<<"accept error, continue next link"<<endl;
    //      continue;
    //    }
    //    int port = ntohs(peer.sin_port);
    //    string ip = inet_ntoa(peer.sin_addr);
    //    cout<<"get a new link, sockfd is "<<linkSock<<endl;
    //    // 连接成功后，创建子进程为客户端提供服务
    //    if(fork() == 0)
    //    {
    //      close(_listenSock);
    //      if(fork() == 0)
    //      {
    //        Service(linkSock, ip, port);
    //      }
    //      exit(0);
    //    }
    //    close(linkSock);
    //    waitpid(-1, nullptr, 0);
    //  }
    //}

    // 多线程版本
    // 启动服务器
    void LoopServer()
    {
      struct sockaddr_in peer;
      memset(&peer, 0, sizeof(peer));
      socklen_t len = sizeof(peer);

      // 不断地监听获取客户端的连接请求
      while(1)
      {
        int linkSock = accept(_listenSock, (struct sockaddr*)&peer, &len);
        // 若该套接字监听失败，继续监听下一个套接字即可
        if(linkSock == -1)
        {
          cout<<"accept error, continue next link"<<endl;
          continue;
        }
        int port = ntohs(peer.sin_port);
        string ip = inet_ntoa(peer.sin_addr);
        cout<<"get a new link, sockfd is "<<linkSock<<endl;
        // 建立连接后，创建子线程去处理任务
        Param* pm = new Param(linkSock, ip, port);
        pthread_t tid;
        pthread_create(&tid, nullptr, Routine, pm);
      }
    }

    // 子线程处理任务函数
    static void* Routine(void* arg)
    {
      pthread_detach(pthread_self());
      Param* pm = (Param*)arg;
      Service(pm->_sockfd, pm->_ip, pm->_port); 
      delete pm;
      return nullptr;
    }

  private:
    int _port;
    int _listenSock;
};
